package base.thread_example.example04;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 分别给生产者和消费者各一组监视器对象
 *
 * 通过已有的锁获取两组监视器，一组监视生产者，一组监视消费者
 *
 */
public class ProducerAndConsumerWithMultipleConditions {
    public static void main(String[] args) {
        Resource r = new Resource("烤鸭");

        Producer producer = new Producer(r);
        Consumer consumer = new Consumer(r);

        // 创建3生产者
        new Thread(producer, "生产者-1").start();
        new Thread(producer, "生产者-2").start();
        new Thread(producer, "生产者-3").start();
        // 创建3消费者
        new Thread(consumer, "消费者-1").start();
        new Thread(consumer, "消费者-2").start();
        new Thread(consumer, "消费者-3").start();
    }
}


class Producer implements Runnable{
    private Resource r;
    public Producer(Resource r){
        this.r = r;
    }

    @Override
    public void run() {
        while (true){
            try {
                r.set();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable{
    private Resource r;
    public Consumer(Resource r){
        this.r = r;
    }

    @Override
    public void run() {
        while (true){
            try {
                r.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Resource {
    private static final Logger log = LoggerFactory.getLogger(Resource.class);
    private String name;//资源名称
    private int count=1;//资源编号
    private boolean flag = false;//资源标识：一开始表示没有资源
    private static String tempName;//临时生产产品名

    //创建一个锁对象
    private Lock lock = new ReentrantLock();
    //通过已有的锁获取两组监视器，一组监视生产者，一组监视消费者
    Condition producer_condition = lock.newCondition();
    Condition consumer_condition = lock.newCondition();



    public Resource(String name){
        this.name = name;
    }

    // 生产
    public void set() throws InterruptedException {
        lock.lock();
        try {
            while (this.flag){
                producer_condition.await();
            }
            tempName = this.name + count;
            count++;
            this.flag = !this.flag;
            log.info("{} 生产了 {}", Thread.currentThread().getName(), tempName);
            consumer_condition.signal();//去消费者waitSet中唤醒任一线程,不用调用signalAll()唤醒所有
        }finally {
            lock.unlock();
        }
    }

    // 消费
    public void get() throws InterruptedException {
        lock.lock();
        try {
            while (!this.flag){
                consumer_condition.await();
            }
            this.flag = !this.flag;
            log.info("------------------------>{} 消费了 {}", Thread.currentThread().getName(), tempName);
            producer_condition.signal();
        }finally {
            lock.unlock();
        }
    }
}
